﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Data;
using SciLorsGroovesharkAPI.Groove.Functions;
using centrafuse.Plugins;
using System.Threading;
using System.Drawing;

namespace Grooveshark
{
    public partial class Grooveshark
    {
        private CFControls.CFAdvancedList searchResultView;
        private DataTable searchResultsTable;
        private BindingSource searchResultsBindingSource;

        private void SetupSearchResultScreen()
        {
            searchResultView = this.advancedlistArray[CF_getAdvancedListID("searchResultList")];
            searchResultView.DoubleClick += new EventHandler<CFControlsExtender.Listview.ItemArgs>(searchResultView_DoubleClick);
            searchResultView.DataBinding = searchResultsBindingSource;
            searchResultView.Refresh();

            this.CF_createButtonClick("searchResultUpButton", new MouseEventHandler(searchResultUpButton_Click));
            this.CF_createButtonClick("searchResultDownButton", new MouseEventHandler(searchResultDownButton_Click));
            this.CF_createButtonClick("addSelectedButton", new MouseEventHandler(addSelectedButton_Click));
            this.CF_createButtonClick("addAllButton", new MouseEventHandler(addAllButton_Click));
            this.CF_createButtonClick("backToPlaylistButton", new MouseEventHandler(backToPlaylist_Click));
        }

        void searchResultView_DoubleClick(object sender, CFControlsExtender.Listview.ItemArgs e)
        {
            if (searchResultsTable.Rows.Count > e.ItemId)
            {
                DataRow row = searchResultsTable.Rows[e.ItemId];
                object obj = row["Object"];
                if (obj is SearchArtist.SearchArtistResult)
                {
                    CF_systemCommand(CF_Actions.BEEPSOUND);
                    AppendToPlaylist(new SearchArtist.SearchArtistResult[] { obj as SearchArtist.SearchArtistResult });
                }
                else
                {
                    OpenObjectAndDisplay(obj);
                }
            }
        }

        private void OpenObjectAndDisplay(object obj)
        {
            if (obj is Artist)
            {
                PopulateWithAlbums(obj as Artist);
            }
            else if (obj is Album)
            {
                PopulateWithSongsFromAlbum(obj as Album);
            }
            else if (obj is Playlist)
            {
                PopulateWithSongsFromPlaylist(obj as Playlist);
            }
            else if (obj is BackObject)
            {
                BackObject back = obj as BackObject;
                if (back.GoBackTo is Album)
                {
                    PopulateWithAlbums(new Artist((back.GoBackTo as Album).ArtistID, string.Empty));
                    SelectObject(back.GoBackTo);
                }
                else if (back.GoBackTo is Artist)
                {
                    PopulateWithArtists();
                    SelectObject(back.GoBackTo);
                }
            }
            else
                throw new Exception("Unrecognized object type: " + obj.GetType().ToString());

            searchResultView.Refresh();
        }
        

        private void searchResultUpButton_Click(object sender, MouseEventArgs e)
        {
            searchResultView.PageUp();
        }

        private void searchResultDownButton_Click(object sender, MouseEventArgs e)
        {
            searchResultView.PageDown();
        }

        private void addSelectedButton_Click(object sender, MouseEventArgs e)
        {
            int selectedIx = searchResultView.SelectedIndex;
            if (selectedIx != -1)
            {
                DataRow songRow = searchResultsTable.Rows[selectedIx];
                object obj = songRow["Object"];

                if (obj is SearchArtist.SearchArtistResult)
                {
                    AppendToPlaylist(new SearchArtist.SearchArtistResult[] { obj as SearchArtist.SearchArtistResult });
                }
                else
                {
                    PromptAndAppendToPlaylist(UnwrapToSongs(obj));
                }
            }
        }

        private IEnumerable<SearchArtist.SearchArtistResult> UnwrapToSongs(object obj)
        {
            if (currentResults == null)
                throw new Exception("No current results");

            if (obj is SearchArtist.SearchArtistResult)
                return new SearchArtist.SearchArtistResult[] { obj as SearchArtist.SearchArtistResult };
            else if (obj is Album)
            {
                Album album = obj as Album;
                var songs = currentResults.Where(song => song.AlbumID.Equals(album.ID));
                return songs.ToArray();
            }
            else if (obj is Artist)
            {
                Artist artist = obj as Artist;
                var songs = currentResults.Where(song => song.ArtistID.Equals(artist.ID));
                return songs.ToArray();
            }
            else if (obj is Playlist)
            {
                return null; //to implement
            }
            else if (obj is BackObject)
            {
                return new SearchArtist.SearchArtistResult[0];
            }
            else
                throw new Exception("Unrecognized object type: " + obj.GetType().ToString());
                
        }

        private void AppendToPlaylist(IEnumerable<SearchArtist.SearchArtistResult> songs)
        {
            if (songs.Count() > 0)
            {
                foreach (var song in songs)
                {
                    DataRow newRow = playlistTable.NewRow();
                    newRow["Object"] = song;
                    newRow["SongName"] = song.SongName;
                    playlistTable.Rows.Add(newRow);
                }

                IEnumerable<SearchArtist.SearchArtistResult> songsToAppend;
                if (currentSong != null)
                {
                    //grab all the songs we haven't played yet
                    var songNode = shuffledPlaylist.Find(currentSong);
                    if (songNode.Next != null)
                    {
                        //there are songs after the ones we're playing right now
                        var trimmedPlaylist = shuffledPlaylist.TakeWhile(s => s != songNode.Next.Value).ToArray();
                        var remainder = shuffledPlaylist.Where(s => !trimmedPlaylist.Contains(s)).ToArray();

                        shuffledPlaylist = new LinkedList<SearchArtist.SearchArtistResult>(trimmedPlaylist);
                        songsToAppend = songs.Concat(remainder).ToArray();
                    }
                    else
                    {
                        songsToAppend = songs;
                    }
                }
                else
                    songsToAppend = songs;

                songsToAppend = ShuffleSongs(songsToAppend);
                shuffledPlaylist = new LinkedList<SearchArtist.SearchArtistResult>(shuffledPlaylist.Concat(songsToAppend));

                CF_AudioStatus streamStatus = CF_getAudioStatus(audioStream);
                if (streamStatus == CF_AudioStatus.Stopped || streamStatus == CF_AudioStatus.Stalled)
                {
                    if (ShuffleState)
                    {
                        PlaySong(shuffledPlaylist.First.Value);
                    }
                    else
                    {
                        PlaySong(songs.First());
                    }
                }
            }
        }

        private IEnumerable<SearchArtist.SearchArtistResult> ShuffleSongs(IEnumerable<SearchArtist.SearchArtistResult> songsLeftToPlay)
        {
            var r = new Random();
            return songsLeftToPlay.OrderBy(x => r.Next()).ToArray();
        }

        private void PromptAndAppendToPlaylist(IEnumerable<SearchArtist.SearchArtistResult> songs)
        {
            CFDialogParams dialogParams = new CFDialogParams(string.Format("Are you sure you want to add {0} song(s) to the playlist?", songs.Count()));
            DialogResult result = CF_displayDialog(CF_Dialogs.YesNo, dialogParams);
            if (result == System.Windows.Forms.DialogResult.Yes || result == System.Windows.Forms.DialogResult.OK)
            {
                AppendToPlaylist(songs);
            }
        }

        private void backToPlaylist_Click(object sender, MouseEventArgs e)
        {
            ShowPlaylistScreen();
        }

        private void addAllButton_Click(object sender, MouseEventArgs e)
        {
            List<SearchArtist.SearchArtistResult> songsToAdd = new List<SearchArtist.SearchArtistResult>();
            foreach (DataRow dr in searchResultsTable.Rows)
            {
                object obj = dr["Object"];
                songsToAdd.AddRange(UnwrapToSongs(obj));
            }
            PromptAndAppendToPlaylist(songsToAdd);
        }

        private List<SearchArtist.SearchArtistResult> currentResults = null;
        private void PopulateSearchResults(List<SearchArtist.SearchArtistResult> results, bool group)
        {
            searchResultsTable.Clear();
            currentResults = results;

            if (!group)
            {
                foreach (SearchArtist.SearchArtistResult searchResult in results)
                {
                    DataRow newRow = searchResultsTable.NewRow();
                    newRow["Name"] = searchResult.SongName;
                    newRow["Artist"] = searchResult.ArtistName;
                    newRow["Album"] = searchResult.AlbumName;
                    newRow["MetaName"] = string.Empty;
                    newRow["Object"] = searchResult;
                    searchResultsTable.Rows.Add(newRow);
                }
            }
            else
            {
                PopulateWithArtists();
            }
        }

        private void PopulateWithArtists()
        {
            searchResultsTable.Clear();
            var artists = currentResults.Select(song => new Artist(song.ArtistID, song.ArtistName));
            var distinctArtists = artists.Distinct();
            var sortedArtists = distinctArtists.ToList();
            sortedArtists.Sort((artist1, artist2) => artist1.Name.CompareTo(artist2.Name));

            foreach (Artist artist in sortedArtists)
            {
                DataRow newRow = searchResultsTable.NewRow();
                newRow["Name"] = string.Empty;
                newRow["Artist"] = string.Empty;
                newRow["Album"] = string.Empty;
                newRow["MetaName"] = artist.Name;
                newRow["Object"] = artist;
                searchResultsTable.Rows.Add(newRow);
            }
        }

        private void PopulateWithAlbums(Artist artist)
        {
            searchResultsTable.Clear();
            var albums = currentResults.Where(song=> song.ArtistID.Equals(artist.ID)).Select(song => new Album(song.AlbumID, song.AlbumName, song.ArtistID));
            var distinctAlbums = albums.Distinct();
            var sortedAlbums = distinctAlbums.ToList();
            sortedAlbums.Sort((album1, album2) => album1.Name.CompareTo(album2.Name));

            AppendBackRow(artist);

            foreach (Album album in sortedAlbums)
            {
                DataRow newRow = searchResultsTable.NewRow();
                newRow["Name"] = string.Empty;
                newRow["Artist"] = string.Empty;
                newRow["Album"] = string.Empty;
                newRow["MetaName"] = album.Name;
                newRow["Object"] = album;
                searchResultsTable.Rows.Add(newRow);
            }
        }

        private void PopulateWithSongsFromAlbum(Album album)
        {
            searchResultsTable.Clear();
            var songs = currentResults.Where(song => song.AlbumID.Equals(album.ID));
            var sortedSongs = songs.ToList();

            sortedSongs.Sort((song1, song2) =>
            {
                if (string.IsNullOrEmpty(song1.TrackNum))
                {
                    if (string.IsNullOrEmpty(song2.TrackNum))
                        return string.Compare(song1.SongName, song2.SongName);
                    else
                        return 1;
                }
                else
                {
                    if (string.IsNullOrEmpty(song2.TrackNum))
                        return -1;
                    else
                        return string.Compare(song1.TrackNum, song2.TrackNum);
                }
            });

            AppendBackRow(album);

            foreach (SearchArtist.SearchArtistResult searchResult in sortedSongs)
            {
                DataRow newRow = searchResultsTable.NewRow();
                newRow["Name"] = searchResult.SongName;
                newRow["Artist"] = searchResult.ArtistName;
                newRow["Album"] = searchResult.AlbumName;
                newRow["MetaName"] = string.Empty;
                newRow["Object"] = searchResult;
                searchResultsTable.Rows.Add(newRow);
            }
        }

        private void SelectObject(GroovesharkGroupObject groupObject)
        {
            searchResultView.Refresh();
            foreach (DataRow row in searchResultsTable.Rows)
            {
                GroovesharkGroupObject obj = row["Object"] as GroovesharkGroupObject;
                if(obj != null && obj.ID.Equals(groupObject.ID))
                {
                    int index = searchResultsTable.Rows.IndexOf(row);
                    this.BeginInvoke(new MethodInvoker(delegate()
                        {
                            this.searchResultsBindingSource.Position = index;
                            searchResultView.SelectedIndex = index;        
                        }));
                    break;
                }
            }
        }

        private void AppendBackRow(GroovesharkGroupObject groupObj)
        {
            DataRow backRow = searchResultsTable.NewRow();
            backRow["Name"] = string.Empty;
            backRow["Artist"] = string.Empty;
            backRow["Album"] = string.Empty;
            backRow["MetaName"] = "..";
            backRow["Object"] = new BackObject(groupObj);
            searchResultsTable.Rows.Add(backRow);
        }

        private void PopulateWithSongsFromPlaylist(Playlist playlist)
        {
            throw new NotImplementedException();
        }
    }
}
